#include "interval.h"

// Interval Interval::CreateIncludeInterval(const float& f) {
//     Interval a(f, f);
//     // f有至少三位小数，将其用区间包含
//     // if ((int)(f*1000)%10 > 0) {
//     //     a.Setab((int)(f*100-1)/100.0f, (int)(f*100+1)/100.0f);
//     // }
//     return a;
// }

const Interval allnan = Interval(nan(""), nan(""));  // 用NaN初始化防止不小心出错,非法数字

Interval::Interval(double a, double b) :
    a_(a), b_(b) {
        assertInvariant();  // 用非法数字初始化合法
}

double Interval::a() const {
    assertInvariant();
    return a_;
}
double Interval::b() const {
    assertInvariant();
    return b_;
}

BoolInterval Interval::lt(const Interval& that) const {
    assertInvariant();
    that.assertInvariant();

    return BoolInterval(b_ < that.a_, a_ < that.b_);  // 数值比较
}

BoolInterval Interval::eq(const Interval& that) const {
    double alr = abs(b_ - a_);
    double abt = abs(that.b_ - that.a_);
    double mlr = (a_+b_)/2;
    double mbt = (that.a_+that.b_)/2;
    if (abs(alr - abt) < 0.0001 && abs(mlr-mbt) < 0.0001)
        return alltrue;
    return halftrue;
}

Interval Interval::sqrt() const {
    assertInvariant();

    return Interval(sqrtDown(a_), sqrtUp(b_));
}

Interval Interval::isin() const {
    assertInvariant();

    if (b_-a_ <= Pi/2) {
        if (cos(a_) > 0) {
            if (cos(b_) > 0)
                return Interval(sinDown(a_), sinUp(b_));
            else if(cos(b_) < 0)
                return Interval(std::min(sinDown(a_), sinDown(b_)), 1.0f);
            else
                return Interval(sinDown(a_), 1.0f);
        }
        else if (cos(a_) < 0) {
            if (cos(b_) < 0)
                return Interval(sinDown(b_), sinUp(a_));
            else if(cos(b_) > 0)
                return Interval(-1.0f, std::max(sinUp(a_), sinUp(b_)));
            else
                return Interval(-1.0f, sinUp(a_));
        }
        else {
            if (cos(b_) > 0)
                return Interval(-1.0f, sinUp(b_));
            else if(cos(b_) < 0)
                return Interval(sinDown(b_), 1.0f);
            else
                return Interval(-1.0f, 1.0f);
        }
    }
    else {
        return *this;
    }
}

Interval Interval::icos() const {
    assertInvariant();

    if (b_-a_ <= Pi/2) {
        if (-sin(a_) > 0) {
            if (-sin(b_) > 0)
                return Interval(cosDown(a_), cosUp(b_));
            else if(-sin(b_) < 0)
                return Interval(std::min(cosDown(a_), cosDown(b_)), 1.0f);
            else
                return Interval(cosDown(a_), 1.0f);
        }
        else if (-sin(a_) < 0) {
            if (-sin(b_) < 0)
                return Interval(cosDown(b_), cosUp(a_));
            else if(-sin(b_) > 0)
                return Interval(-1.0f, std::max(cosUp(a_), cosUp(b_)));
            else
                return Interval(-1.0f, cosUp(a_));
        }
        else {
            if (-sin(b_) > 0)
                return Interval(-1.0f, cosUp(b_));
            else if(-sin(b_) < 0)
                return Interval(cosDown(b_), 1.0f);
            else
                return Interval(-1.0f, 1.0f);
        }
    }
    else {
        return *this;
    }
}

Interval Interval::itan() const {
    if (tan(a_) > tan(b_))
        return *this;
    return Interval(tanDown(a_), tanUp(b_));
}

Interval Interval::ilog() const {
    return Interval(logDown(a_), logUp(b_));
}

Interval& Interval::operator+=(const Interval& that) {
    assertInvariant(); that.assertInvariant();

    a_ = addDown(a_, that.a_);
    b_ = addUp(b_, that.b_);
    return *this;
}
Interval& Interval::operator-=(const Interval& that) {
    assertInvariant(); that.assertInvariant();

    a_ = subDown(a_, that.b_);
    b_ = subUp(b_, that.a_);
    return *this;
}
Interval& Interval::operator*=(const Interval& that) {
    assertInvariant(); that.assertInvariant();

    const Interval pab(a_, b_);
    const Interval qab(that.a_, that.b_);
    a_ = std::min(std::min(mulDown(pab.unsafeA(), qab.unsafeA()), mulDown(pab.unsafeA(), qab.unsafeB())), std::min(mulDown(pab.unsafeB(), qab.unsafeA()), mulDown(pab.unsafeB(), qab.unsafeB())));
    b_ = std::max(std::max(mulUp(pab.unsafeA(), qab.unsafeA()), mulUp(pab.unsafeA(), qab.unsafeB())), std::max(mulUp(pab.unsafeB(), qab.unsafeA()), mulUp(pab.unsafeB(), qab.unsafeB())));

    return *this;
}
Interval& Interval::operator/=(const Interval& that) {
    assertInvariant(); that.assertInvariant();

    Interval pab(a_, b_);
    Interval qab(1/that.a_, 1/that.b_);
    a_ = std::min(std::min(mulDown(pab.unsafeA(), qab.unsafeA()), mulDown(pab.unsafeA(), qab.unsafeB())), std::min(mulDown(pab.unsafeB(), qab.unsafeA()), mulDown(pab.unsafeB(), qab.unsafeB())));
    b_ = std::max(std::max(mulUp(pab.unsafeA(), qab.unsafeA()), mulUp(pab.unsafeA(), qab.unsafeB())), std::max(mulUp(pab.unsafeB(), qab.unsafeA()), mulUp(pab.unsafeB(), qab.unsafeB())));
    return *this;
}

Interval& Interval::operator++() {
    assertInvariant();

    ++a_;
    ++b_;
    return *this;
}
Interval& Interval::operator--() {
    assertInvariant();

    --a_;
    --b_;
    return *this;
}

void swap(Interval& a, Interval& b) {
    a.assertInvariant(); b.assertInvariant();

    using std::swap;
    swap(a.a_, b.a_);
    swap(a.b_, b.b_);
}

bool operator==(const Interval& l, const Interval& r) {
    l.assertInvariant(); r.assertInvariant();

    return l.a_ == r.a_ && l.b_ == r.b_;
}

inline void Interval::assertInvariant() const {
  //assert(std::isnan(a_) == std::isnan(b_));  // 都是数或者都不是数
  //assert(std::isnan(a_) || a_ <= b_);   // 都是正常数值就要满足a<b
}

